﻿using System.Collections.Generic;
using Comdiv.QWeb.Diagnostics;
using Comdiv.QWeb.Events;
using Comdiv.QWeb.Serialization.Attributes;
using Comdiv.QWeb.Utils;

namespace Comdiv.QWeb.ViewEngine {
	public class QViewFactory : IQViewFactory, IRegistryBound {
		private readonly IDictionary<string, IQViewDescriptor> cache = new Dictionary<string, IQViewDescriptor>();
		private IQViewCompiler compiler;
		private QWebServiceRegistry registry;

		#region IQViewFactory Members

		/// <summary>
		/// Resets views, if full is True - cache will be totally droped, if false - it marked to check new files, use FULL when U sure that 
		/// something changed, that system cannot assume
		/// </summary>
		/// <param name="full"></param>
		public void Refresh(bool full) {
			lock (this) {
				if (full) {
					cache.Clear();
				}
				else {
					foreach (var vd in cache) {
						vd.Value.Recompile();
					}
				}
			}
		}

		public void SetView(string name, IQViewDescriptor descriptor) {
			cache[name] = descriptor;
		}

		public IQView GetView(QViewContext context) {
			lock (this) {
				var ctx = context.GetNormalizedContext();
				if (null == ctx.Factory) ctx.Factory = this;
				if (null == ctx.Output) {
					var qc = ctx.Context ?? QWebContext.Current;
					if (null != qc) {
						ctx.Output = qc.Output;
					}
				}
				if (!cache.ContainsKey(ctx.Name)) {
					cache[ctx.Name] = compiler.GetDescriptor(ctx.Name);


					cache[ctx.Name].Stats = new QViewStats();
					Registry.Statistics.QViewEngineStatistics.ViewStats[ctx.Name] = cache[ctx.Name].Stats;
				}
				var desc = cache[ctx.Name];
				ctx.ViewDescriptor = desc;
				var result = desc.GetView();
				result.SetViewContext(ctx);
				Registry.Statistics.QViewEngineStatistics.Activations++;
				return result;
			}
		}

		#endregion

		#region IRegistryBound Members

		public QWebServiceRegistry Registry {
			get { return registry; }
		}

		public void SetRegistry(QWebServiceRegistry registry) {
			this.registry = registry;
			compiler = registry.QViewCompiler;
			this.registry.Events.Add(new QWebViewFactory_Reseter(this));
		}

		#endregion

		#region Nested type: QWebViewFactory_Reseter

		[Serialize]
		private class QWebViewFactory_Reseter : QWebEventHandlerBase<ResetEvent> {
			public readonly string ResetOption = "qview.factory";
			public readonly string Type = "QWebViewFactory_Reseter";
			private readonly IQViewFactory factory;

			public QWebViewFactory_Reseter(IQViewFactory factory) {
				this.factory = factory;
			}

			public override void Process(ResetEvent e) {
				if (e.Data.IsSet(ResetOption)) {
					factory.Refresh(false);
					if (e.Context.get("fulldrop").toBool()) {
						if (factory is IRegistryBound) {
							((IRegistryBound) factory).Registry.QViewCompiler.Reset();
						}
						factory.Refresh(true);
					}
					e.Result.InvokeList.Add(this);
				}
			}
		}

		#endregion
	}
}